package com.softcomputer.rpt.ejb;

import com.softcomputer.rpt.entity.ExCourse;
import com.softcomputer.rpt.entity.ExCoursesContainer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;

@Stateless
@XmlSeeAlso(ExCoursesContainer.class)
public class ExchangeSession implements Serializable {

    @PersistenceContext(unitName = "Exchanger")
    private EntityManager em;
    private List values;
    private List<String> currency;
    private static final Log LOG = LogFactory.getLog(ExchangeSession.class);
    private static Unmarshaller unmarshaller;
    private static JAXBContext jaxbContext;
    private static SchemaFactory schemaFactory;
    private static FileOutputStream str;
    private static Map<String, Float> rateMap;

    public void setEntityManager(EntityManager entityManager) {
        em = entityManager;
    }

    public List<ExCourse> retrieve() {

        List<ExCourse> exchangeCoursesList;

        exchangeCoursesList = em.createNamedQuery("ExCourse.findAll").getResultList();

        return exchangeCoursesList;
    }

    public List<BigDecimal> getDollarRate() {

        values = new ArrayList<BigDecimal>();
        List<ExCourse> courses;

        try {
            courses = em.createNamedQuery("ExCourse.findAll").getResultList();
        } catch (Exception exception) {
            LOG.error("Unable to read dollar rates: " + exception.getMessage());
            return new ArrayList<BigDecimal>();
        }

        for (ExCourse exCourse : courses) {
            values.add(exCourse.getIndollars());
        }
        return values;
    }

    public List<String> getCurrency() {

        currency = new ArrayList<String>();
        List<ExCourse> courses;

        try {
            courses = em.createNamedQuery("ExCourse.findAll").getResultList();
        } catch (Exception exception) {
            LOG.error("Unable to read currency list: " + exception.getMessage());
            return new ArrayList<String>();
        }

        for (ExCourse exCourse : courses) {
            currency.add(exCourse.getCurrency());
        }
        return currency;
    }

    public float getExchangeRateFromDB(String fromCurrency, String toCurrency) {

        float rate;

        LOG.info("Exchange rate calculation requested (DB)...");

        List<ExCourse> fromCurrencyList = null;
        List<ExCourse> toCurrencyList = null;

        Query fromCurrencyQuery = em.createNamedQuery("ExCourse.findByCurrency").setParameter("currency", fromCurrency);
        Query toCurrencyQuery = em.createNamedQuery("ExCourse.findByCurrency").setParameter("currency", toCurrency);

        try {
            fromCurrencyList = fromCurrencyQuery.getResultList();
            toCurrencyList = toCurrencyQuery.getResultList();
        } catch (Exception exception) {
            LOG.error("Unable to read rates for selected currencies: " + exception.getMessage());
        }

        rate = toCurrencyList.get(0).getIndollars() / fromCurrencyList.get(0).getIndollars();
        LOG.info("Exchange rate calculated: " + rate);
        return rate;
    }

    public float getExchangeRateFromXml(String fromCurrency, String toCurrency) {

        LOG.info("Exchange rate calculation requested (XML)...");

        float result = rateMap.get(toCurrency) / rateMap.get(fromCurrency);

        LOG.info("Counted exchange rate - " + result);

        return result;
    }

    public BigDecimal exchange(String amount, float exchangeRate) {

        try {
            float floatAmount = Float.parseFloat(amount);
        } catch (NumberFormatException e) {
            LOG.error("Wrong number format for exchange amount " + e.getMessage());
            return new BigDecimal(0);
        }

        return new BigDecimal(exchangeRate).multiply(new BigDecimal(amount));
    }

    public ExchangeSession() {

        LOG.info("Creating rate map from courses.xml");
        rateMap = new HashMap<String, Float>();

        File coursesXmlFile = new File("courses.xml");

        try {
            LOG.info("Preparing unmarshall XML file " + coursesXmlFile.getName());

            jaxbContext = JAXBContext.newInstance(ExchangeSession.class);
            unmarshaller = jaxbContext.createUnmarshaller();

            LOG.info("Creating schema factory...");
            schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema schema = schemaFactory.newSchema(new File("schema.xsd"));
            unmarshaller.setSchema(schema);

            LOG.info("Unmarshalling XML...");
            ExCoursesContainer container = (ExCoursesContainer) unmarshaller.unmarshal(coursesXmlFile);

            List<ExCourse> coursesList = container.getList();
            LOG.info(coursesList == null ? "Unmarshalling failed..." : "Unmarshalling finished propertly");

            for (ExCourse exCourse : coursesList) {
                rateMap.put(exCourse.getCurrency(), exCourse.getIndollars());
            }

        } catch (JAXBException e) {
            LOG.error("Unmarshalling error: " + e.getMessage());
        } catch (NullPointerException e) {
            LOG.error("Null pointer exception while unmarshalling: " + e.getMessage());
        } catch (SAXException e) {
            LOG.error("SAXEXception: " + e.getMessage());
        }

    }
}
